<!DOCTYPE html>
<html prefix="
og: http://ogp.me/ns#
article: http://ogp.me/ns/article#
" lang="zh_cn">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Extending Nikola | vincent blog</title>
<link href="../../assets/css/all-nocdn.css" rel="stylesheet" type="text/css">
<link rel="alternate" type="application/rss+xml" title="RSS" href="../../rss.xml">
<link rel="canonical" href="https://wisonwang.github.io/pages/extending/">
<!--[if lt IE 9]><script src="/assets/js/html5.js"></script><![endif]--><meta name="author" content="The Nikola Team">
<meta property="og:site_name" content="vincent blog">
<meta property="og:title" content="Extending Nikola">
<meta property="og:url" content="https://wisonwang.github.io/pages/extending/">
<meta property="og:description" content="Extending Nikola




Version:7.8.14

Author:Roberto Alsina &lt;ralsina@netmanagers.com.ar&gt;




目录

Extending Nikola
Command Plugins
TemplateSystem Plugins
Task Plugins
PageCompiler Plugins
RestExtension ">
<meta property="og:type" content="article">
<meta property="article:published_time" content="2012-03-30T23:00:00-03:00">
<meta name="author" content="The Nikola Team">
<meta property="og:site_name" content="vincent blog">
<meta property="og:title" content="Extending Nikola">
<meta property="og:url" content="https://wisonwang.github.io/pages/extending/">
<meta property="og:description" content="Extending Nikola




Version:7.8.14

Author:Roberto Alsina &lt;ralsina@netmanagers.com.ar&gt;




目录

Extending Nikola
Command Plugins
TemplateSystem Plugins
Task Plugins
PageCompiler Plugins
RestExtension ">
<meta property="og:type" content="article">
<meta property="article:published_time" content="2012-03-30T23:00:00-03:00">
</head>
<body>
    <section class="social"><ul>
<li><a href="../../index.html" title="Home"><i class="icon-home"></i></a></li>
            <li><a href="../../archive.html" title="文章存档"><i class="icon-archive"></i></a></li>
            <li><a href="../../categories/" title="标签"><i class="icon-tags"></i></a></li>
            <li><a href="../about" title="About"><i class="icon-about"></i></a></li>
            <li><a href="../../rss.xml" title="RSS 源"><i class="icon-rss"></i></a></li>
            <li><a href="https://twitter.com/wisonwang" title="My Twitter"><i class="icon-twitter"></i></a></li>
            <li><a href="https://github.com/wisonwang" title="My Github"><i class="icon-github"></i></a></li>

        </ul></section><section class="page-content"><div class="content" rel="main">
<article class="storypage" itemscope="itemscope" itemtype="http://schema.org/Article"><header><h1 class="p-name entry-title" itemprop="headline name">Extending Nikola</h1>

        
    </header><div itemprop="articleBody text">
    <div>
<div class="section" id="extending-nikola">
<h2><a class="toc-backref" href="#id2">Extending Nikola</a></h2>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name">
<col class="field-body">
<tbody valign="top">
<tr class="field">
<th class="field-name">Version:</th>
<td class="field-body">7.8.14</td>
</tr>
<tr class="field">
<th class="field-name">Author:</th>
<td class="field-body">Roberto Alsina &lt;<a class="reference external" href="mailto:ralsina@netmanagers.com.ar">ralsina@netmanagers.com.ar</a>&gt;</td>
</tr>
</tbody>
</table>
<div class="contents alert alert-info pull-right topic" id="id1">
<p class="topic-title first">目录</p>
<ul class="simple">
<li>
<a class="reference internal" href="#extending-nikola" id="id2">Extending Nikola</a><ul>
<li><a class="reference internal" href="#command-plugins" id="id3">Command Plugins</a></li>
<li><a class="reference internal" href="#templatesystem-plugins" id="id4">TemplateSystem Plugins</a></li>
<li><a class="reference internal" href="#task-plugins" id="id5">Task Plugins</a></li>
<li><a class="reference internal" href="#pagecompiler-plugins" id="id6">PageCompiler Plugins</a></li>
<li><a class="reference internal" href="#restextension-plugins" id="id7">RestExtension Plugins</a></li>
<li><a class="reference internal" href="#markdownextension-plugins" id="id8">MarkdownExtension Plugins</a></li>
<li><a class="reference internal" href="#signalhandler-plugins" id="id9">SignalHandler Plugins</a></li>
<li><a class="reference internal" href="#configplugin-plugins" id="id10">ConfigPlugin Plugins</a></li>
<li><a class="reference internal" href="#postscanner-plugins" id="id11">PostScanner Plugins</a></li>
</ul>
</li>
<li><a class="reference internal" href="#plugin-index" id="id12">Plugin Index</a></li>
<li><a class="reference internal" href="#path-link-resolution-mechanism" id="id13">Path/Link Resolution Mechanism</a></li>
<li><a class="reference internal" href="#template-hooks" id="id14">Template Hooks</a></li>
<li>
<a class="reference internal" href="#shortcodes" id="id15">Shortcodes</a><ul>
<li><a class="reference internal" href="#template-based-shortcodes" id="id16">Template-based Shortcodes</a></li>
</ul>
</li>
<li><a class="reference internal" href="#state-and-cache" id="id17">State and Cache</a></li>
</ul>
</div>
<p class="lead">Nikola is extensible. Almost all its functionality is based on plugins,
and you can add your own or replace the provided ones.</p>
<p>Plugins consist of a metadata file (with <tt class="docutils literal">.plugin</tt> extension) and
a Python module (a <tt class="docutils literal">.py</tt> file) or package (a folder containing
a <tt class="docutils literal">__init__.py</tt> file.</p>
<p>To use a plugin in your site, you just have to put it in a <tt class="docutils literal">plugins</tt>
folder in your site.</p>
<p>Plugins come in various flavours, aimed at extending different aspects
of Nikola.</p>
<div class="section" id="command-plugins">
<h3><a class="toc-backref" href="#id3">Command Plugins</a></h3>
<p>When you run <tt class="docutils literal">nikola <span class="pre">--help</span></tt> you will see something like this:</p>
<pre class="code console"><a name="rest_code_9163f08b3599455496da088b4ee74a56-1"></a><span class="gp">$</span> nikola <span class="nb">help</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-2"></a><span class="go">Nikola is a tool to create static websites and blogs. For full documentation and more</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-3"></a><span class="go">information, please visit https://getnikola.com/</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-4"></a>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-5"></a>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-6"></a><span class="go">Available commands:</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-7"></a><span class="go">nikola auto                 automatically detect site changes, rebuild</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-8"></a><span class="go">                            and optionally refresh a browser</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-9"></a><span class="go">nikola bootswatch_theme     given a swatch name from bootswatch.com and a</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-10"></a><span class="go">                            parent theme, creates a custom theme</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-11"></a><span class="go">nikola build                run tasks</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-12"></a><span class="go">nikola check                check links and files in the generated site</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-13"></a><span class="go">nikola clean                clean action / remove targets</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-14"></a><span class="go">nikola console              start an interactive python console with access to</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-15"></a><span class="go">                            your site and configuration</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-16"></a><span class="go">nikola deploy               deploy the site</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-17"></a><span class="go">nikola dumpdb               dump dependency DB</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-18"></a><span class="go">nikola forget               clear successful run status from internal DB</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-19"></a><span class="go">nikola help                 show help</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-20"></a><span class="go">nikola ignore               ignore task (skip) on subsequent runs</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-21"></a><span class="go">nikola import_blogger       import a blogger dump</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-22"></a><span class="go">nikola import_feed          import a RSS/Atom dump</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-23"></a><span class="go">nikola import_wordpress     import a WordPress dump</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-24"></a><span class="go">nikola init                 create a Nikola site in the specified folder</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-25"></a><span class="go">nikola list                 list tasks from dodo file</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-26"></a><span class="go">nikola mincss               apply mincss to the generated site</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-27"></a><span class="go">nikola new_post             create a new blog post or site page</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-28"></a><span class="go">nikola run                  run tasks</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-29"></a><span class="go">nikola serve                start the test webserver</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-30"></a><span class="go">nikola strace               use strace to list file_deps and targets</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-31"></a><span class="go">nikola theme                manage themes</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-32"></a><span class="go">nikola version              print the Nikola version number</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-33"></a>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-34"></a><span class="go">nikola help                 show help / reference</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-35"></a><span class="go">nikola help &lt;command&gt;       show command usage</span>
<a name="rest_code_9163f08b3599455496da088b4ee74a56-36"></a><span class="go">nikola help &lt;task-name&gt;     show task usage</span>
</pre>
<p>That will give you a list of all available commands in your version of Nikola.
Each and every one of those is a plugin. Let's look at a typical example:</p>
<p>First, the <tt class="docutils literal">serve.plugin</tt> file:</p>
<pre class="code ini"><a name="rest_code_a0685e38b79640f4b865c6f251fc5bb4-1"></a><span class="k">[Core]</span>
<a name="rest_code_a0685e38b79640f4b865c6f251fc5bb4-2"></a><span class="na">Name</span> <span class="o">=</span> <span class="s">serve</span>
<a name="rest_code_a0685e38b79640f4b865c6f251fc5bb4-3"></a><span class="na">Module</span> <span class="o">=</span> <span class="s">serve</span>
<a name="rest_code_a0685e38b79640f4b865c6f251fc5bb4-4"></a>
<a name="rest_code_a0685e38b79640f4b865c6f251fc5bb4-5"></a><span class="k">[Documentation]</span>
<a name="rest_code_a0685e38b79640f4b865c6f251fc5bb4-6"></a><span class="na">Author</span> <span class="o">=</span> <span class="s">Roberto Alsina</span>
<a name="rest_code_a0685e38b79640f4b865c6f251fc5bb4-7"></a><span class="na">Version</span> <span class="o">=</span> <span class="s">0.1</span>
<a name="rest_code_a0685e38b79640f4b865c6f251fc5bb4-8"></a><span class="na">Website</span> <span class="o">=</span> <span class="s">https://getnikola.com</span>
<a name="rest_code_a0685e38b79640f4b865c6f251fc5bb4-9"></a><span class="na">Description</span> <span class="o">=</span> <span class="s">Start test server.</span>
</pre>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">If you want to publish your plugin on the Plugin Index, <a class="reference external" href="https://github.com/getnikola/plugins/blob/master/README.md">read
the docs for the Index</a>
(and the .plugin file examples and explanations).</p>
</div>
<p>For your own plugin, just change the values in a sensible way. The
<tt class="docutils literal">Module</tt> will be used to find the matching Python module, in this case
<tt class="docutils literal">serve.py</tt>, from which this is the interesting bit:</p>
<pre class="code python"><a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-1"></a><span class="kn">from</span> <span class="nn">nikola.plugin_categories</span> <span class="kn">import</span> <span class="n">Command</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-2"></a>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-3"></a><span class="c1"># You have to inherit Command for this to be a</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-4"></a><span class="c1"># command plugin:</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-5"></a>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-6"></a><span class="k">class</span> <span class="nc">CommandServe</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-7"></a>    <span class="sd">"""Start test server."""</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-8"></a>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-9"></a>    <span class="n">name</span> <span class="o">=</span> <span class="s2">"serve"</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-10"></a>    <span class="n">doc_usage</span> <span class="o">=</span> <span class="s2">"[options]"</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-11"></a>    <span class="n">doc_purpose</span> <span class="o">=</span> <span class="s2">"start the test webserver"</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-12"></a>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-13"></a>    <span class="n">cmd_options</span> <span class="o">=</span> <span class="p">(</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-14"></a>        <span class="p">{</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-15"></a>            <span class="s1">'name'</span><span class="p">:</span> <span class="s1">'port'</span><span class="p">,</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-16"></a>            <span class="s1">'short'</span><span class="p">:</span> <span class="s1">'p'</span><span class="p">,</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-17"></a>            <span class="s1">'long'</span><span class="p">:</span> <span class="s1">'port'</span><span class="p">,</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-18"></a>            <span class="s1">'default'</span><span class="p">:</span> <span class="mi">8000</span><span class="p">,</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-19"></a>            <span class="s1">'type'</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-20"></a>            <span class="s1">'help'</span><span class="p">:</span> <span class="s1">'Port number (default: 8000)'</span><span class="p">,</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-21"></a>        <span class="p">},</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-22"></a>        <span class="p">{</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-23"></a>            <span class="s1">'name'</span><span class="p">:</span> <span class="s1">'address'</span><span class="p">,</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-24"></a>            <span class="s1">'short'</span><span class="p">:</span> <span class="s1">'a'</span><span class="p">,</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-25"></a>            <span class="s1">'long'</span><span class="p">:</span> <span class="s1">'--address'</span><span class="p">,</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-26"></a>            <span class="s1">'type'</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-27"></a>            <span class="s1">'default'</span><span class="p">:</span> <span class="s1">'127.0.0.1'</span><span class="p">,</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-28"></a>            <span class="s1">'help'</span><span class="p">:</span> <span class="s1">'Address to bind (default: 127.0.0.1)'</span><span class="p">,</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-29"></a>        <span class="p">},</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-30"></a>    <span class="p">)</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-31"></a>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-32"></a>    <span class="k">def</span> <span class="nf">_execute</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">args</span><span class="p">):</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-33"></a>        <span class="sd">"""Start test server."""</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-34"></a>        <span class="n">out_dir</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'OUTPUT_FOLDER'</span><span class="p">]</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-35"></a>        <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isdir</span><span class="p">(</span><span class="n">out_dir</span><span class="p">):</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-36"></a>            <span class="nb">print</span><span class="p">(</span><span class="s2">"Error: Missing '</span><span class="si">{0}</span><span class="s2">' folder?"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">out_dir</span><span class="p">))</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-37"></a>        <span class="k">else</span><span class="p">:</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-38"></a>            <span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">out_dir</span><span class="p">)</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-39"></a>            <span class="n">httpd</span> <span class="o">=</span> <span class="n">HTTPServer</span><span class="p">((</span><span class="n">options</span><span class="p">[</span><span class="s1">'address'</span><span class="p">],</span> <span class="n">options</span><span class="p">[</span><span class="s1">'port'</span><span class="p">]),</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-40"></a>                            <span class="n">OurHTTPRequestHandler</span><span class="p">)</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-41"></a>            <span class="n">sa</span> <span class="o">=</span> <span class="n">httpd</span><span class="o">.</span><span class="n">socket</span><span class="o">.</span><span class="n">getsockname</span><span class="p">()</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-42"></a>            <span class="nb">print</span><span class="p">(</span><span class="s2">"Serving HTTP on"</span><span class="p">,</span> <span class="n">sa</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="s2">"port"</span><span class="p">,</span> <span class="n">sa</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">"..."</span><span class="p">)</span>
<a name="rest_code_88d9630bdbbb4bb7a88f4f735ab1b5b0-43"></a>            <span class="n">httpd</span><span class="o">.</span><span class="n">serve_forever</span><span class="p">()</span>
</pre>
<p>As mentioned above, a plugin can have options, which the user can see by doing
<tt class="docutils literal">nikola help command</tt> and can later use, for example:</p>
<pre class="code console"><a name="rest_code_1859dc5cf2004185abc1ee4b1316f124-1"></a><span class="gp">$</span> nikola <span class="nb">help</span> serve
<a name="rest_code_1859dc5cf2004185abc1ee4b1316f124-2"></a><span class="go">Purpose: start the test webserver</span>
<a name="rest_code_1859dc5cf2004185abc1ee4b1316f124-3"></a><span class="go">Usage:   nikola serve [options]</span>
<a name="rest_code_1859dc5cf2004185abc1ee4b1316f124-4"></a>
<a name="rest_code_1859dc5cf2004185abc1ee4b1316f124-5"></a><span class="go">Options:</span>
<a name="rest_code_1859dc5cf2004185abc1ee4b1316f124-6"></a><span class="go">-p ARG, --port=ARG        Port number (default: 8000)</span>
<a name="rest_code_1859dc5cf2004185abc1ee4b1316f124-7"></a><span class="go">-a ARG, ----address=ARG   Address to bind (default: 127.0.0.1)</span>
<a name="rest_code_1859dc5cf2004185abc1ee4b1316f124-8"></a>
<a name="rest_code_1859dc5cf2004185abc1ee4b1316f124-9"></a><span class="gp">$</span> nikola serve -p <span class="m">9000</span>
<a name="rest_code_1859dc5cf2004185abc1ee4b1316f124-10"></a><span class="go">Serving HTTP on 127.0.0.1 port 9000 ...</span>
</pre>
<p>So, what can you do with commands? Well, anything you want, really. I have implemented
a sort of planet using it. So, be creative, and if you do something interesting,
let me know ;-)</p>
</div>
<div class="section" id="templatesystem-plugins">
<h3><a class="toc-backref" href="#id4">TemplateSystem Plugins</a></h3>
<p>Nikola supports Mako and Jinja2. If you prefer some other templating
system, then you will have to write a <tt class="docutils literal">TemplateSystem</tt> plugin. Here's how they work.
First, you have to create a <tt class="docutils literal">.plugin</tt> file. Here's the one for the Mako plugin:</p>
<pre class="code ini"><a name="rest_code_6443e5e0cb4045f9874d43abb2c5e421-1"></a><span class="k">[Core]</span>
<a name="rest_code_6443e5e0cb4045f9874d43abb2c5e421-2"></a><span class="na">Name</span> <span class="o">=</span> <span class="s">mako</span>
<a name="rest_code_6443e5e0cb4045f9874d43abb2c5e421-3"></a><span class="na">Module</span> <span class="o">=</span> <span class="s">mako</span>
<a name="rest_code_6443e5e0cb4045f9874d43abb2c5e421-4"></a>
<a name="rest_code_6443e5e0cb4045f9874d43abb2c5e421-5"></a><span class="k">[Documentation]</span>
<a name="rest_code_6443e5e0cb4045f9874d43abb2c5e421-6"></a><span class="na">Author</span> <span class="o">=</span> <span class="s">Roberto Alsina</span>
<a name="rest_code_6443e5e0cb4045f9874d43abb2c5e421-7"></a><span class="na">Version</span> <span class="o">=</span> <span class="s">0.1</span>
<a name="rest_code_6443e5e0cb4045f9874d43abb2c5e421-8"></a><span class="na">Website</span> <span class="o">=</span> <span class="s">https://getnikola.com</span>
<a name="rest_code_6443e5e0cb4045f9874d43abb2c5e421-9"></a><span class="na">Description</span> <span class="o">=</span> <span class="s">Support for Mako templates.</span>
</pre>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">If you want to publish your plugin on the Plugin Index, <a class="reference external" href="https://github.com/getnikola/plugins/blob/master/README.md">read
the docs for the Index</a>
(and the .plugin file examples and explanations).</p>
</div>
<p>You will have to replace "mako" with your template system's name, and other data
in the obvious ways.</p>
<p>The "Module" option is the name of the module, which has to look something like this,
a stub for a hypothetical system called "Templater":</p>
<pre class="code python"><a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-1"></a><span class="kn">from</span> <span class="nn">nikola.plugin_categories</span> <span class="kn">import</span> <span class="n">TemplateSystem</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-2"></a>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-3"></a><span class="c1"># You have to inherit TemplateSystem</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-4"></a>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-5"></a><span class="k">class</span> <span class="nc">TemplaterTemplates</span><span class="p">(</span><span class="n">TemplateSystem</span><span class="p">):</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-6"></a>    <span class="sd">"""Wrapper for Templater templates."""</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-7"></a>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-8"></a>    <span class="c1"># name has to match Name in the .plugin file</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-9"></a>    <span class="n">name</span> <span class="o">=</span> <span class="s2">"templater"</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-10"></a>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-11"></a>    <span class="c1"># A list of directories where the templates will be</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-12"></a>    <span class="c1"># located. Most template systems have some sort of</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-13"></a>    <span class="c1"># template loading tool that can use this.</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-14"></a>    <span class="k">def</span> <span class="nf">set_directories</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">directories</span><span class="p">,</span> <span class="n">cache_folder</span><span class="p">):</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-15"></a>        <span class="sd">"""Sets the list of folders where templates are located and cache."""</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-16"></a>        <span class="k">pass</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-17"></a>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-18"></a>    <span class="c1"># You *must* implement this, even if to return []</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-19"></a>    <span class="c1"># It should return a list of all the files that,</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-20"></a>    <span class="c1"># when changed, may affect the template's output.</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-21"></a>    <span class="c1"># usually this involves template inheritance and</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-22"></a>    <span class="c1"># inclusion.</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-23"></a>    <span class="k">def</span> <span class="nf">template_deps</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">template_name</span><span class="p">):</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-24"></a>        <span class="sd">"""Returns filenames which are dependencies for a template."""</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-25"></a>        <span class="k">return</span> <span class="p">[]</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-26"></a>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-27"></a>    <span class="k">def</span> <span class="nf">render_template</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">template_name</span><span class="p">,</span> <span class="n">output_name</span><span class="p">,</span> <span class="n">context</span><span class="p">):</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-28"></a>        <span class="sd">"""Renders template to a file using context.</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-29"></a>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-30"></a><span class="sd">        This must save the data to output_name *and* return it</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-31"></a><span class="sd">        so that the caller may do additional processing.</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-32"></a><span class="sd">        """</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-33"></a>        <span class="k">pass</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-34"></a>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-35"></a>    <span class="c1"># The method that does the actual rendering.</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-36"></a>    <span class="c1"># template_name is the name of the template file,</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-37"></a>    <span class="c1"># context is a dictionary containing the data the template</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-38"></a>    <span class="c1"># uses for rendering.</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-39"></a>    <span class="k">def</span> <span class="nf">render_template_to_string</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">template</span><span class="p">,</span> <span class="n">context</span><span class="p">):</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-40"></a>        <span class="sd">"""Renders template to a string using context. """</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-41"></a>        <span class="k">pass</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-42"></a>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-43"></a>    <span class="k">def</span> <span class="nf">inject_directory</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">directory</span><span class="p">):</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-44"></a>        <span class="sd">"""Injects the directory with the lowest priority in the</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-45"></a><span class="sd">        template search mechanism."""</span>
<a name="rest_code_bdc1c6cdba784196aa32a3fd84409203-46"></a>        <span class="k">pass</span>
</pre>
<p>You can see a real example in <a class="reference external" href="https://github.com/getnikola/nikola/blob/master/nikola/plugins/template/jinja.py">the Jinja plugin</a></p>
</div>
<div class="section" id="task-plugins">
<h3><a class="toc-backref" href="#id5">Task Plugins</a></h3>
<p>If you want to do something that depends on the data in your site, you
probably want to do a <tt class="docutils literal">Task</tt> plugin, which will make it be part of the
<tt class="docutils literal">nikola build</tt> command. These are the currently available tasks, all
provided by plugins:</p>
<div class="sidebar">
<p class="first sidebar-title">Other Tasks</p>
<p class="last">There are also <tt class="docutils literal">LateTask</tt> plugins, which are executed later,
and <tt class="docutils literal">TaskMultiplier</tt> plugins that take a task and create
more tasks out of it.</p>
</div>
<pre class="code console"><a name="rest_code_ff8c484d157c49778a1047e62f130887-1"></a><span class="gp">$</span> nikola list
<a name="rest_code_ff8c484d157c49778a1047e62f130887-2"></a><span class="go">Scanning posts....done!</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-3"></a><span class="go">build_bundles</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-4"></a><span class="go">build_less</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-5"></a><span class="go">copy_assets</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-6"></a><span class="go">copy_files</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-7"></a><span class="go">post_render</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-8"></a><span class="go">redirect</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-9"></a><span class="go">render_archive</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-10"></a><span class="go">render_galleries</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-11"></a><span class="go">render_galleries_clean</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-12"></a><span class="go">render_indexes</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-13"></a><span class="go">render_listings</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-14"></a><span class="go">render_pages</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-15"></a><span class="go">render_posts</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-16"></a><span class="go">render_rss</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-17"></a><span class="go">render_site</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-18"></a><span class="go">render_sources</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-19"></a><span class="go">render_tags</span>
<a name="rest_code_ff8c484d157c49778a1047e62f130887-20"></a><span class="go">sitemap</span>
</pre>
<p>These have access to the <tt class="docutils literal">site</tt> object which contains your timeline and
your configuration.</p>
<p>The critical bit of Task plugins is their <tt class="docutils literal">gen_tasks</tt> method, which <tt class="docutils literal">yields</tt>
<a class="reference external" href="http://pydoit.org/tasks.html">doit tasks</a>.</p>
<p>The details of how to handle dependencies, etc., are a bit too much for this
document, so I'll just leave you with an example, the <tt class="docutils literal">copy_assets</tt> task.
First the <tt class="docutils literal">task_copy_assets.plugin</tt> file, which you should copy and edit
in the logical ways:</p>
<pre class="code ini"><a name="rest_code_df2a1ff7f7af492fa870d33f12c36429-1"></a><span class="k">[Core]</span>
<a name="rest_code_df2a1ff7f7af492fa870d33f12c36429-2"></a><span class="na">Name</span> <span class="o">=</span> <span class="s">copy_assets</span>
<a name="rest_code_df2a1ff7f7af492fa870d33f12c36429-3"></a><span class="na">Module</span> <span class="o">=</span> <span class="s">task_copy_assets</span>
<a name="rest_code_df2a1ff7f7af492fa870d33f12c36429-4"></a>
<a name="rest_code_df2a1ff7f7af492fa870d33f12c36429-5"></a><span class="k">[Documentation]</span>
<a name="rest_code_df2a1ff7f7af492fa870d33f12c36429-6"></a><span class="na">Author</span> <span class="o">=</span> <span class="s">Roberto Alsina</span>
<a name="rest_code_df2a1ff7f7af492fa870d33f12c36429-7"></a><span class="na">Version</span> <span class="o">=</span> <span class="s">0.1</span>
<a name="rest_code_df2a1ff7f7af492fa870d33f12c36429-8"></a><span class="na">Website</span> <span class="o">=</span> <span class="s">https://getnikola.com</span>
<a name="rest_code_df2a1ff7f7af492fa870d33f12c36429-9"></a><span class="na">Description</span> <span class="o">=</span> <span class="s">Copy theme assets into output.</span>
</pre>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">If you want to publish your plugin on the Plugin Index, <a class="reference external" href="https://github.com/getnikola/plugins/blob/master/README.md">read
the docs for the Index</a>
(and the .plugin file examples and explanations).</p>
</div>
<p>And the <tt class="docutils literal">task_copy_assets.py</tt> file, in its entirety:</p>
<pre class="code python"><a name="rest_code_8bb96308c707433d89d1acf4837c35d4-1"></a><span class="kn">import</span> <span class="nn">os</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-2"></a>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-3"></a><span class="kn">from</span> <span class="nn">nikola.plugin_categories</span> <span class="kn">import</span> <span class="n">Task</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-4"></a><span class="kn">from</span> <span class="nn">nikola</span> <span class="kn">import</span> <span class="n">utils</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-5"></a>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-6"></a><span class="c1"># Have to inherit Task to be a task plugin</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-7"></a><span class="k">class</span> <span class="nc">CopyAssets</span><span class="p">(</span><span class="n">Task</span><span class="p">):</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-8"></a>    <span class="sd">"""Copy theme assets into output."""</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-9"></a>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-10"></a>    <span class="n">name</span> <span class="o">=</span> <span class="s2">"copy_assets"</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-11"></a>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-12"></a>    <span class="c1"># This yields the tasks</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-13"></a>    <span class="k">def</span> <span class="nf">gen_tasks</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-14"></a>        <span class="sd">"""Create tasks to copy the assets of the whole theme chain.</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-15"></a>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-16"></a><span class="sd">        If a file is present on two themes, use the version</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-17"></a><span class="sd">        from the "youngest" theme.</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-18"></a><span class="sd">        """</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-19"></a>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-20"></a>        <span class="c1"># I put all the configurations and data the plugin uses</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-21"></a>        <span class="c1"># in a dictionary because utils.config_changed will</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-22"></a>        <span class="c1"># make it so that if these change, this task will be</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-23"></a>        <span class="c1"># marked out of date, and run again.</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-24"></a>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-25"></a>        <span class="n">kw</span> <span class="o">=</span> <span class="p">{</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-26"></a>            <span class="s2">"themes"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">THEMES</span><span class="p">,</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-27"></a>            <span class="s2">"output_folder"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'OUTPUT_FOLDER'</span><span class="p">],</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-28"></a>            <span class="s2">"filters"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'FILTERS'</span><span class="p">],</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-29"></a>        <span class="p">}</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-30"></a>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-31"></a>        <span class="n">tasks</span> <span class="o">=</span> <span class="p">{}</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-32"></a>        <span class="k">for</span> <span class="n">theme_name</span> <span class="ow">in</span> <span class="n">kw</span><span class="p">[</span><span class="s1">'themes'</span><span class="p">]:</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-33"></a>            <span class="n">src</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">utils</span><span class="o">.</span><span class="n">get_theme_path</span><span class="p">(</span><span class="n">theme_name</span><span class="p">),</span> <span class="s1">'assets'</span><span class="p">)</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-34"></a>            <span class="n">dst</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">kw</span><span class="p">[</span><span class="s1">'output_folder'</span><span class="p">],</span> <span class="s1">'assets'</span><span class="p">)</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-35"></a>            <span class="k">for</span> <span class="n">task</span> <span class="ow">in</span> <span class="n">utils</span><span class="o">.</span><span class="n">copy_tree</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">dst</span><span class="p">):</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-36"></a>                <span class="k">if</span> <span class="n">task</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span> <span class="ow">in</span> <span class="n">tasks</span><span class="p">:</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-37"></a>                    <span class="k">continue</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-38"></a>                <span class="n">tasks</span><span class="p">[</span><span class="n">task</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]]</span> <span class="o">=</span> <span class="n">task</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-39"></a>                <span class="n">task</span><span class="p">[</span><span class="s1">'uptodate'</span><span class="p">]</span> <span class="o">=</span> <span class="n">task</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'uptodate'</span><span class="p">,</span> <span class="p">[])</span> <span class="o">+</span> \
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-40"></a>                    <span class="p">[</span><span class="n">utils</span><span class="o">.</span><span class="n">config_changed</span><span class="p">(</span><span class="n">kw</span><span class="p">)]</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-41"></a>                <span class="n">task</span><span class="p">[</span><span class="s1">'basename'</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-42"></a>                <span class="c1"># If your task generates files, please do this.</span>
<a name="rest_code_8bb96308c707433d89d1acf4837c35d4-43"></a>                <span class="k">yield</span> <span class="n">utils</span><span class="o">.</span><span class="n">apply_filters</span><span class="p">(</span><span class="n">task</span><span class="p">,</span> <span class="n">kw</span><span class="p">[</span><span class="s1">'filters'</span><span class="p">])</span>
</pre>
</div>
<div class="section" id="pagecompiler-plugins">
<h3><a class="toc-backref" href="#id6">PageCompiler Plugins</a></h3>
<p>These plugins implement markup languages, they take sources for posts or pages and
create HTML or other output files. A good example is <a class="reference external" href="https://github.com/getnikola/plugins/tree/master/v7/misaka">the misaka plugin</a> or the built-in
compiler plugins.</p>
<p>They must provide:</p>
<dl class="docutils">
<dt><tt class="docutils literal">compile</tt></dt>
<dd>Function that builds a file.</dd>
<dt><tt class="docutils literal">create_post</tt></dt>
<dd>Function that creates an empty file with some metadata in it.</dd>
</dl>
<p>If the compiler produces something other than HTML files, it should also implement <tt class="docutils literal">extension</tt> which
returns the preferred extension for the output file.</p>
<p>These plugins can also be used to extract metadata from a file. To do so, the
plugin may implement <tt class="docutils literal">read_metadata</tt> that will return a dict containing the
metadata contained in the file.</p>
</div>
<div class="section" id="restextension-plugins">
<h3><a class="toc-backref" href="#id7">RestExtension Plugins</a></h3>
<p>Implement directives for reStructuredText, see <a class="reference external" href="https://github.com/getnikola/nikola/blob/master/nikola/plugins/compile/rest/media.py">media.py</a> for a simple example.</p>
<p>If your output depends on a config value, you need to make your post record a
dependency on a pseudo-path, like this:</p>
<pre class="code text"><a name="rest_code_05ec9d18b3cf4599a47dfb8077d19b56-1"></a>####MAGIC####CONFIG:OPTIONNAME
</pre>
<p>Then, whenever the <tt class="docutils literal">OPTIONNAME</tt> option is changed in conf.py, the file will be rebuilt.</p>
<p>If your directive depends or may depend on the whole timeline (like the
<tt class="docutils literal"><span class="pre">post-list</span></tt> directive, where adding new posts to the site could make it
stale), you should record a dependency on the pseudo-path
<tt class="docutils literal"><span class="pre">####MAGIC####TIMELINE</span></tt>.</p>
</div>
<div class="section" id="markdownextension-plugins">
<h3><a class="toc-backref" href="#id8">MarkdownExtension Plugins</a></h3>
<p>Implement Markdown extensions, see <a class="reference external" href="https://github.com/getnikola/nikola/blob/master/nikola/plugins/compile/markdown/mdx_nikola.py">mdx_nikola.py</a> for a simple example.</p>
<p>Note that Python markdown extensions are often also available as separate
packages. This is only meant to ship extensions along with Nikola.</p>
</div>
<div class="section" id="signalhandler-plugins">
<h3><a class="toc-backref" href="#id9">SignalHandler Plugins</a></h3>
<p>These plugins extend the <tt class="docutils literal">SignalHandler</tt> class and connect to one or more
signals via <a class="reference external" href="http://pythonhosted.org/blinker/">blinker</a>.</p>
<p>The easiest way to do this is to reimplement <tt class="docutils literal">set_site()</tt> and just connect to
whatever signals you want there.</p>
<p>Currently Nikola emits the following signals:</p>
<dl class="docutils">
<dt><tt class="docutils literal">sighandlers_loaded</tt></dt>
<dd>Right after SignalHandler plugin activation.</dd>
<dt><tt class="docutils literal">initialized</tt></dt>
<dd>When all tasks are loaded.</dd>
<dt><tt class="docutils literal">configured</tt></dt>
<dd>When all the configuration file is processed. Note that plugins are activated before this is emitted.</dd>
<dt><tt class="docutils literal">scanned</tt></dt>
<dd>After posts are scanned.</dd>
<dt>
<tt class="docutils literal">new_post</tt> / <tt class="docutils literal">new_page</tt>
</dt>
<dd>When a new post is created, using the <tt class="docutils literal">nikola new_post</tt>/<tt class="docutils literal">nikola new_page</tt> commands.  The signal
data contains the path of the file, and the metadata file (if there is one).</dd>
<dt>
<tt class="docutils literal">existing_post</tt> / <tt class="docutils literal">existing_page</tt>
</dt>
<dd>When a new post fails to be created due to a title conflict. Contains the same data as <tt class="docutils literal">new_post</tt>.</dd>
<dt><tt class="docutils literal">deployed</tt></dt>
<dd>
<p class="first">When the <tt class="docutils literal">nikola deploy</tt> command is run, and there is at least one new
entry/post since <tt class="docutils literal">last_deploy</tt>.  The signal data is of the form:</p>
<pre class="last literal-block">
{
 'last_deploy: # datetime object for the last deployed time,
 'new_deploy': # datetime object for the current deployed time,
 'clean': # whether there was a record of a last deployment,
 'deployed': # all files deployed after the last deploy,
 'undeployed': # all files not deployed since they are either future posts/drafts
}
</pre>
</dd>
<dt><tt class="docutils literal">compiled</tt></dt>
<dd>
<p class="first">When a post/page is compiled from its source to html, before anything else is done with it.  The signal
data is in the form:</p>
<pre class="last literal-block">
{
 'source': # the path to the source file
 'dest': # the path to the cache file for the post/page
 'post': # the Post object for the post/page
}
</pre>
</dd>
</dl>
<p>One example is the <a class="reference external" href="https://github.com/getnikola/plugins/tree/master/v6/deploy_hooks">deploy_hooks plugin.</a></p>
</div>
<div class="section" id="configplugin-plugins">
<h3><a class="toc-backref" href="#id10">ConfigPlugin Plugins</a></h3>
<p>Does nothing specific, can be used to modify the site object (and thus the config).</p>
<p>Put all the magic you want in <tt class="docutils literal">set_site()</tt>, and don’t forget to run the one
from <tt class="docutils literal">super()</tt>. Example  plugin: <a class="reference external" href="https://github.com/getnikola/plugins/tree/master/v7/navstories">navstories</a></p>
</div>
<div class="section" id="postscanner-plugins">
<h3><a class="toc-backref" href="#id11">PostScanner Plugins</a></h3>
<p>Get posts and pages from "somewhere" to be added to the timeline.
The only currently existing plugin of this kind reads them from disk.</p>
</div>
</div>
<div class="section" id="plugin-index">
<h2><a class="toc-backref" href="#id12">Plugin Index</a></h2>
<p>There is a <a class="reference external" href="https://plugins.getnikola.com/">plugin index</a>, which stores all
of the plugins for Nikola people wanted to share with the world.</p>
<p>You may want to read the <a class="reference external" href="https://github.com/getnikola/plugins/blob/master/README.md">README for the Index</a> if you want to
publish your package there.</p>
</div>
<div class="section" id="path-link-resolution-mechanism">
<h2><a class="toc-backref" href="#id13">Path/Link Resolution Mechanism</a></h2>
<p>Any plugin can register a function using <tt class="docutils literal">Nikola.register_path_handler</tt> to
allow resolution of paths and links. These are useful for templates, which
can access them via <tt class="docutils literal">_link</tt>.</p>
<p>For example, you can always get a link to the path for the feed of the "foo" tag
by using <tt class="docutils literal"><span class="pre">_link('tag_rss',</span> 'foo')</tt> or the <tt class="docutils literal"><span class="pre">link://tag_rss/foo</span></tt> URL.</p>
<p>Here's the relevant code from the tag plugin.</p>
<pre class="code python"><a name="rest_code_d11194c39fe845988ae4cd9c7092f628-1"></a><span class="c1"># In set_site</span>
<a name="rest_code_d11194c39fe845988ae4cd9c7092f628-2"></a><span class="n">site</span><span class="o">.</span><span class="n">register_path_handler</span><span class="p">(</span><span class="s1">'tag_rss'</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tag_rss_path</span><span class="p">)</span>
<a name="rest_code_d11194c39fe845988ae4cd9c7092f628-3"></a>
<a name="rest_code_d11194c39fe845988ae4cd9c7092f628-4"></a><span class="c1"># And these always take name and lang as arguments and returl a list of</span>
<a name="rest_code_d11194c39fe845988ae4cd9c7092f628-5"></a><span class="c1"># path elements.</span>
<a name="rest_code_d11194c39fe845988ae4cd9c7092f628-6"></a><span class="k">def</span> <span class="nf">tag_rss_path</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">lang</span><span class="p">):</span>
<a name="rest_code_d11194c39fe845988ae4cd9c7092f628-7"></a>    <span class="k">return</span> <span class="p">[</span><span class="n">_f</span> <span class="k">for</span> <span class="n">_f</span> <span class="ow">in</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'TRANSLATIONS'</span><span class="p">][</span><span class="n">lang</span><span class="p">],</span>
<a name="rest_code_d11194c39fe845988ae4cd9c7092f628-8"></a>                          <span class="bp">self</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'TAG_PATH'</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">slugify_name</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">lang</span><span class="p">)</span> <span class="o">+</span> <span class="s2">".xml"</span><span class="p">]</span> <span class="k">if</span>
<a name="rest_code_d11194c39fe845988ae4cd9c7092f628-9"></a>            <span class="n">_f</span><span class="p">]</span>
</pre>
</div>
<div class="section" id="template-hooks">
<h2><a class="toc-backref" href="#id14">Template Hooks</a></h2>
<p>Plugins can use a hook system for adding stuff into templates.  In order to use
it, a plugin must register itself.  The following hooks currently exist:</p>
<ul class="simple">
<li>
<tt class="docutils literal">extra_head</tt> (not equal to the config option!)</li>
<li>
<tt class="docutils literal">body_end</tt> (not equal to the config option!)</li>
<li><tt class="docutils literal">page_header</tt></li>
<li><tt class="docutils literal">menu</tt></li>
<li>
<tt class="docutils literal">menu_alt</tt> (right-side menu in bootstrap, after <tt class="docutils literal">menu</tt> in base)</li>
<li><tt class="docutils literal">page_footer</tt></li>
</ul>
<p>For example, in order to register a script into <tt class="docutils literal">extra_head</tt>:</p>
<pre class="code python"><a name="rest_code_0f30e84b1aa14c6a9dcf4f5c460ff3f0-1"></a><span class="c1"># In set_site</span>
<a name="rest_code_0f30e84b1aa14c6a9dcf4f5c460ff3f0-2"></a><span class="n">site</span><span class="o">.</span><span class="n">template_hooks</span><span class="p">[</span><span class="s1">'extra_head'</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">'&lt;script src="/assets/js/fancyplugin.js"&gt;'</span><span class="p">)</span>
</pre>
<p>There is also another API available.  It allows use of dynamically generated
HTML:</p>
<pre class="code python"><a name="rest_code_b34380c0dab74391b35551585a71dd96-1"></a><span class="c1"># In set_site</span>
<a name="rest_code_b34380c0dab74391b35551585a71dd96-2"></a><span class="k">def</span> <span class="nf">generate_html_bit</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">ftype</span><span class="o">=</span><span class="s1">'js'</span><span class="p">):</span>
<a name="rest_code_b34380c0dab74391b35551585a71dd96-3"></a>    <span class="sd">"""Generate HTML for an asset."""</span>
<a name="rest_code_b34380c0dab74391b35551585a71dd96-4"></a>    <span class="k">return</span> <span class="s1">'&lt;script src="/assets/</span><span class="si">{t}</span><span class="s1">/</span><span class="si">{n}</span><span class="s1">.</span><span class="si">{t}</span><span class="s1">"&gt;'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">n</span><span class="o">=</span><span class="n">name</span><span class="p">,</span> <span class="n">t</span><span class="o">=</span><span class="n">ftype</span><span class="p">)</span>
<a name="rest_code_b34380c0dab74391b35551585a71dd96-5"></a>
<a name="rest_code_b34380c0dab74391b35551585a71dd96-6"></a><span class="n">site</span><span class="o">.</span><span class="n">template_hooks</span><span class="p">[</span><span class="s1">'extra_head'</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">generate_html_bit</span><span class="p">,</span> <span class="kc">False</span><span class="p">,</span> <span class="s1">'fancyplugin'</span><span class="p">,</span> <span class="n">ftype</span><span class="o">=</span><span class="s1">'js'</span><span class="p">)</span>
</pre>
<p>The second argument to <tt class="docutils literal">append()</tt> is used to determine whether the function
needs access to the current template context and the site.  If it is set to
<tt class="docutils literal">True</tt>, the function will also receive <tt class="docutils literal">site</tt> and <tt class="docutils literal">context</tt> keyword
arguments.  Example use:</p>
<pre class="code python"><a name="rest_code_a47cd8e639234fbe89b7fe32b83b862d-1"></a><span class="c1"># In set_site</span>
<a name="rest_code_a47cd8e639234fbe89b7fe32b83b862d-2"></a><span class="k">def</span> <span class="nf">greeting</span><span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="n">endswith</span><span class="o">=</span><span class="s1">''</span><span class="p">,</span> <span class="n">site</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">context</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<a name="rest_code_a47cd8e639234fbe89b7fe32b83b862d-3"></a>    <span class="sd">"""Greet someone."""</span>
<a name="rest_code_a47cd8e639234fbe89b7fe32b83b862d-4"></a>    <span class="k">if</span> <span class="n">context</span><span class="p">[</span><span class="s1">'lang'</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'en'</span><span class="p">:</span>
<a name="rest_code_a47cd8e639234fbe89b7fe32b83b862d-5"></a>        <span class="n">greet</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">'Hello'</span>
<a name="rest_code_a47cd8e639234fbe89b7fe32b83b862d-6"></a>    <span class="k">elif</span> <span class="n">context</span><span class="p">[</span><span class="s1">'lang'</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'es'</span><span class="p">:</span>
<a name="rest_code_a47cd8e639234fbe89b7fe32b83b862d-7"></a>        <span class="n">greet</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">'¡Hola'</span>
<a name="rest_code_a47cd8e639234fbe89b7fe32b83b862d-8"></a>
<a name="rest_code_a47cd8e639234fbe89b7fe32b83b862d-9"></a>    <span class="n">t</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">' BLOG_TITLE = </span><span class="si">{0}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">site</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'BLOG_TITLE'</span><span class="p">](</span><span class="n">context</span><span class="p">[</span><span class="s1">'lang'</span><span class="p">]))</span>
<a name="rest_code_a47cd8e639234fbe89b7fe32b83b862d-10"></a>
<a name="rest_code_a47cd8e639234fbe89b7fe32b83b862d-11"></a>    <span class="k">return</span> <span class="sa">u</span><span class="s1">'&lt;h3&gt;</span><span class="si">{greet}</span><span class="s1"> </span><span class="si">{addr}{endswith}</span><span class="s1">&lt;/h3&gt;'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">greet</span><span class="o">=</span><span class="n">greet</span><span class="p">,</span> <span class="n">addr</span><span class="o">=</span><span class="n">addr</span><span class="p">,</span>
<a name="rest_code_a47cd8e639234fbe89b7fe32b83b862d-12"></a>    <span class="n">endswith</span><span class="o">=</span><span class="n">endswith</span><span class="p">)</span> <span class="o">+</span> <span class="n">t</span>
<a name="rest_code_a47cd8e639234fbe89b7fe32b83b862d-13"></a>
<a name="rest_code_a47cd8e639234fbe89b7fe32b83b862d-14"></a><span class="n">site</span><span class="o">.</span><span class="n">template_hooks</span><span class="p">[</span><span class="s1">'page_header'</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">greeting</span><span class="p">,</span> <span class="kc">True</span><span class="p">,</span> <span class="sa">u</span><span class="s1">'Nikola Tesla'</span><span class="p">,</span> <span class="n">endswith</span><span class="o">=</span><span class="sa">u</span><span class="s1">'!'</span><span class="p">)</span>
</pre>
<p>Dependencies for template hooks:</p>
<ul class="simple">
<li>if the input is a string, the string value, alongside arguments to <tt class="docutils literal">append</tt>, is used for calculating dependencies</li>
<li>if the input is a callable, it attempts <tt class="docutils literal">input.template_registry_identifier</tt>, then <tt class="docutils literal">input.__doc__</tt>, and if neither is available, it uses a static string.</li>
</ul>
<p>Make sure to provide at least a docstring, or a identifier, to ensure rebuilds work properly.</p>
</div>
<div class="section" id="shortcodes">
<h2><a class="toc-backref" href="#id15">Shortcodes</a></h2>
<p>Some (hopefully all) markup compilers support shortcodes in these forms:</p>
<pre class="literal-block">
{{% foo %}}  # No arguments
    {{% foo bar %}}  # One argument, containing "bar"
    {{% foo bar baz=bat %}}  # Two arguments, one containing "bar", one called "baz" containing "bat"

    {{% foo %}}Some text{{% /foo %}}  # one argument called "data" containing "Some text"
</pre>
<p>So, if you are creating a plugin that generates markup, it may be a good idea
to register it as a shortcode in addition of to restructured text directive or
markdown extension, thus making it available to all markup formats.</p>
<p>To implement your own shortcodes from a plugin, you can create a plugin inheriting <tt class="docutils literal">ShortcodePlugin</tt> and
from its <tt class="docutils literal">set_site</tt> method,  call</p>
<p><tt class="docutils literal">Nikola.register_shortcode(name, func)</tt> with the following arguments:</p>
<dl class="docutils">
<dt>
<tt class="docutils literal">name</tt>:</dt>
<dd>Name of the shortcode ("foo" in the examples above)</dd>
<dt>
<tt class="docutils literal">func</tt>:</dt>
<dd>A function that will handle the shortcode</dd>
</dl>
<p>The shortcode handler <strong>must</strong> return a two-element tuple, <tt class="docutils literal">(output, dependencies)</tt></p>
<dl class="docutils">
<dt>
<tt class="docutils literal">output</tt>:</dt>
<dd>The text that will replace the shortcode in the document.</dd>
<dt>
<tt class="docutils literal">dependencies</tt>:</dt>
<dd>A list of all the files on disk which will make the output be considered
out of date. For example, if the shortcode uses a template, it should be
the path to the template file.</dd>
</dl>
<p>The shortcode handler <strong>must</strong> accept the following named arguments (or
variable keyword arguments):</p>
<dl class="docutils">
<dt>
<tt class="docutils literal">site</tt>:</dt>
<dd>An instance of the Nikola class, to access site state</dd>
<dt>
<tt class="docutils literal">data</tt>:</dt>
<dd>If the shortcut is used as opening/closing tags, it will be the text
between them, otherwise <tt class="docutils literal">None</tt>.</dd>
<dt>
<tt class="docutils literal">lang</tt>:</dt>
<dd>The current language.</dd>
</dl>
<p>If the shortcode tag has arguments of the form <tt class="docutils literal">foo=bar</tt> they will be
passed as named arguments. Everything else will be passed as positional
arguments in the function call.</p>
<p>So, for example:</p>
<pre class="literal-block">
{{% foo bar baz=bat beep %}}Some text{{% /foo %}}
</pre>
<p>Assuming you registered <tt class="docutils literal">foo_handler</tt> as the handler function for the
shortcode named <tt class="docutils literal">foo</tt>, this will result in the following call when the above
shortcode is encountered:</p>
<pre class="literal-block">
foo_handler("bar", "beep", baz="bat", data="Some text", site=whatever)
</pre>
<div class="section" id="template-based-shortcodes">
<h3><a class="toc-backref" href="#id16">Template-based Shortcodes</a></h3>
<p>Another way to define a new shortcode is to add a template file to the
<tt class="docutils literal">shortcodes</tt> directory of your site. The template file must have the
shortcode name as the basename and the extension <tt class="docutils literal">.tmpl</tt>. For example, if you
want to add a new shortcode named <tt class="docutils literal">foo</tt>, create the template file as
<tt class="docutils literal">shortcodes/foo.tmpl</tt>.</p>
<p>When the shortcode is encountered, the matching template will be rendered with
its context provided by the arguments given in the shortcode. Keyword arguments
are passed directly, i.e. the key becomes the variable name in the template
namespace with a matching string value. Non-keyword arguments are passed as
string values in a tuple named <tt class="docutils literal">_args</tt>. As for normal shortcodes with a
handler function, <tt class="docutils literal">site</tt> and <tt class="docutils literal">data</tt> will be added to the keyword arguments.</p>
<p>Example:</p>
<p>The following shortcode:</p>
<pre class="code text"><a name="rest_code_3e361df4b2b043689ac89461b2fa4d4d-1"></a>{{% foo bar="baz" spam %}}
</pre>
<p>With a template in <tt class="docutils literal">shortcodes/foo.tmpl</tt> with this content (using Jinja2
syntax in this example)</p>
<pre class="code jinja"><a name="rest_code_9683bdfed28d43e0ad4ad72dc2eafaa8-1"></a><span class="x">&lt;div class="</span><span class="cp">{{</span> <span class="nv">_args</span><span class="o">[</span><span class="m">0</span><span class="o">]</span> <span class="k">if</span> <span class="nv">_args</span> <span class="k">else</span> <span class="s1">'ham'</span> <span class="cp">}}</span><span class="x">"&gt;</span><span class="cp">{{</span> <span class="nv">bar</span> <span class="cp">}}</span><span class="x">&lt;/div&gt;</span>
</pre>
<p>Will result in this output</p>
<pre class="code html"><a name="rest_code_dfc47c7cffbb47198dfa3ae54ee08697-1"></a><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"spam"</span><span class="p">&gt;</span>baz<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</pre>
</div>
</div>
<div class="section" id="state-and-cache">
<h2><a class="toc-backref" href="#id17">State and Cache</a></h2>
<p>Sometimes your plugins will need to cache things to speed up further actions. Here are the conventions for that:</p>
<ul class="simple">
<li>If it's a file, put it somewhere in <tt class="docutils literal"><span class="pre">self.site.config['CACHE_FOLDER']</span></tt> (defaults to <tt class="docutils literal">cache/</tt>.</li>
<li>If it's a value, use <tt class="docutils literal">self.site.cache.set(key, value)</tt> to set it and <tt class="docutils literal">self.site.cache.get(key)</tt> to get it.
The key should be a string, the value should be json-encodable (so, be careful with datetime objects)</li>
</ul>
<p>The values and files you store there can <strong>and will</strong> be deleted sometimes by the user. They should always be
things you can reconstruct without lossage. They are throwaways.</p>
<p>On the other hand, sometimes you want to save something that is <strong>not</strong> a throwaway. These are things that may
change the output, so the user should not delete them. We call that <strong>state</strong>. To save state:</p>
<ul class="simple">
<li>If it's a file, put it somewhere in the working directory. Try not to do that please.</li>
<li>If it's a value, use <tt class="docutils literal">self.site.state.set(key, value)</tt> to set it and <tt class="docutils literal">self.state.cache.get(key)</tt> to get it.
The key should be a string, the value should be json-encodable (so, be careful with datetime objects)</li>
</ul>
<p>The <tt class="docutils literal">cache</tt> and <tt class="docutils literal">state</tt> objects are rather simplistic, and that's intentional. They have no default values: if
the key is not there, you will get <tt class="docutils literal">None</tt> and like it. They are meant to be both threadsafe, but hey, who can
guarantee that sort of thing?</p>
<p>There are no sections, and no access protection, so let's not use it to store passwords and such. Use responsibly.</p>
</div>
</div>
    </div>
</article><footer id="footer"><p>Contents © 2020         <a href="mailto:fangfu2012@gmail.com">vincent wang</a> - Powered by         <a href="https://getnikola.com" rel="nofollow">Nikola</a>         </p>
            
        </footer>
</div>
    </section><script src="../../assets/js/all-nocdn.js" type="text/javascript"></script><script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"> </script><script type="text/x-mathjax-config">
    MathJax.Hub.Config({tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}});
    </script><script type="text/javascript">
            $(function(){
                $('.timeago').timeago();
            });
        </script>
</body>
</html>
